﻿using System;
using System.Text;
using System.Collections;

using Path = System.IO.Path;

namespace System.Web.ScriptBuilder
{
	class ScriptChunk
	{
		private static readonly string ReferenceElement = "<reference path=\"";
#if DEBUG
		private static readonly string UnresolvedElement = "<unresolved path=\"";
		private static readonly string UnresolvedEndElement = "\"/>";
#endif
		private static readonly string[] EmptyDependencies = new string[0];

		public int Order;
		public string SourcePath;
		public string Code;
		public string[] Dependencies;
		public string[] UnresolvedDependencies;
		public short DependencyDepth;

		public ScriptChunk(string code, string source)
		{
			this.SourcePath = source ?? string.Empty;
			this.Code = code ?? string.Empty;
			this.Dependencies = EmptyDependencies;
			UnresolvedDependencies = EmptyDependencies;
			ExtractDependencies(code);

			if (this.Dependencies.Length == 0)
				this.DependencyDepth = 0;
			else
				this.DependencyDepth = -1;
		}

		public ScriptChunk(string code)
			: this(code, null)
		{
		}

		public void WriteTo(StringBuilder output)
		{
#if DEBUG
			output.AppendLine("/*");
			output.Append("		");
			output.AppendLine(this.SourcePath);
			output.AppendLine("*/");

			foreach (var unresolved in this.UnresolvedDependencies)
			{
				if (unresolved == null)
					continue;

				output.Append("/* ");
				output.Append(UnresolvedElement);
				output.Append(unresolved);
				output.Append(UnresolvedEndElement);
				output.AppendLine(" */");
			}
#endif
			if (this.Code != null)
				output.AppendLine(this.Code);
		}
		public int GetSize()
		{

#if DEBUG
			var baseSize = 15 + this.SourcePath.Length; // comment with source path
			foreach (var unresolved in this.UnresolvedDependencies)
			{
				if (unresolved == null)
					continue;

				baseSize += 3 + UnresolvedElement.Length + unresolved.Length + UnresolvedEndElement.Length + 3 + 2;
			}
#else
			var baseSize = 2;
#endif
			if (this.Code == null)
				return baseSize;
			else
				return this.Code.Length + baseSize;
		}

		private void ExtractDependencies(string code)
		{
			var lastIndex = 0;

			var refs = (ArrayList)null;

			// searching for /// <reference path="../my/myscript.js" />
			while (lastIndex != -1)
			{
				var commentLine = lastIndex = code.IndexOf("///", lastIndex);
				if (commentLine == -1)
					continue;
				var endOfLine = lastIndex = code.IndexOf('\n', commentLine);
				var commentLength = endOfLine - commentLine;
				if (commentLength < 0) // eof
					commentLength = code.Length - commentLine;

				var referenceEl = code.IndexOf(ReferenceElement, commentLine, commentLength);
				if (referenceEl == -1)
					continue;

				var pathStart = referenceEl + ReferenceElement.Length;
				var pathEnd = code.IndexOf('\"', pathStart);
				var path = code.Substring(pathStart, pathEnd - pathStart);

				if (refs == null)
					refs = new ArrayList(10);

				if (!Path.IsPathRooted(path))
				{
					if (string.IsNullOrEmpty(this.SourcePath))
						throw new Exception(Loc.GetString("Exception_ScriptComposerCantResolveDependencyFileDoesNotHaveSource"));

					var currentDir = Path.GetDirectoryName(this.SourcePath);
					path = Path.GetFullPath(Path.Combine(currentDir, path));
					refs.Add(path);
				}
				else
					refs.Add(path);
			}

			if (refs != null)
				this.Dependencies = (string[])refs.ToArray(typeof(string));
		}
	}
}
